-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feat(multiple_inherent_impl): Add config option to target specific scope #15843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(multiple_inherent_impl): Add config option to target specific scope #15843
Conversation
rustbot has assigned @samueltardieu. Use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution. There are some things that need to be changed in the way the configuration option is parsed (and output in messages) so that lower-case versions "crate", "file", and "module" can be used instead of a mixed-case one.
clippy_lints/src/inherent_impl.rs
Outdated
/// | ||
/// The config option controls the scope at which multiple inherent impl blocks for the same | ||
/// struct are linted, allowing values of "module" (only within the same module), "file" | ||
/// (within the same file), or "crate" (anywhere in the crate, default). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those lowercase values are not currently recognized (yet), see other comment.
struct T; | ||
|
||
impl S { | ||
fn fisrt() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo? (several occurrences)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update. Here are a new round of comments, the PR is starting to look good.
clippy_config/src/conf.rs
Outdated
/// A list of paths to types that should be treated as if they do not contain interior mutability | ||
#[lints(borrow_interior_mutable_const, declare_interior_mutable_const, ifs_same_cond, mutable_key_type)] | ||
ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()]), | ||
/// Sets the scope at which duplicate impl blocks for the same type are linted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
/// Sets the scope at which duplicate impl blocks for the same type are linted. | |
/// Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted. |
clippy_lints/src/inherent_impl.rs
Outdated
Entry::Vacant(e) => { | ||
// Store the id for the first impl block of this type. The span is retrieved lazily. | ||
e.insert(IdOrSpan::Id(impl_id)); | ||
e.insert((IdOrSpan::Id(impl_id), criterion.clone())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be no need to insert the criterion as part of the value (while it is useful as part of the key). Can't you just keep inserting the IdOrSpan
as was done before? Also, this would let you remove the .clone()
and write match type_map.entry((impl_ty, criterion)) {
above.
clippy_lints/src/inherent_impl.rs
Outdated
Entry::Occupied(mut e) => { | ||
if let Some(span) = get_impl_span(cx, impl_id) { | ||
let first_span = match *e.get() { | ||
let first_span = match e.get().0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also restore the dereference once you remove the criterion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also please squash the commits?
clippy_lints/src/inherent_impl.rs
Outdated
if let Node::Item(&Item { | ||
kind: ItemKind::Impl(_impl_id), | ||
span, | ||
.. | ||
}) = cx.tcx.hir_node(hir_id) | ||
{ | ||
Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).name.clone()) | ||
} else { | ||
// We know we are working on an impl, so the pattern matching can | ||
// not fail | ||
unreachable!() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if let Node::Item(&Item { | |
kind: ItemKind::Impl(_impl_id), | |
span, | |
.. | |
}) = cx.tcx.hir_node(hir_id) | |
{ | |
Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).name.clone()) | |
} else { | |
// We know we are working on an impl, so the pattern matching can | |
// not fail | |
unreachable!() | |
} | |
let span = cx.tcx.hir_span(hir_id); | |
Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).name.clone()) |
clippy_lints/src/inherent_impl.rs
Outdated
|| is_lint_allowed( | ||
cx, | ||
MULTIPLE_INHERENT_IMPL, | ||
cx.tcx.local_def_id_to_hir_id(id), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will not work if #[expect]
is used on the type definition, as the expectation will not be fulfilled. It would probably be better to call clippy_utils::fulfill_or_allowed(…)
. This must be done only when you know for sure that the lint would be emitted if not allowed or expected.
Could you add some tests with #[expect]
to check that this works as expected (ah ah)?
I need help to understand what's wrong with my test file. I looked at how But, when I use
I don't understand why I get this... The way I wrote it is probably not the intended way, but then how? Thank you! |
21e0f33
to
97de6e0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like only a minor comment change is necessary to ensure consistency.
I also find the IdOrSpan
construct a bit useless, but that is not on you as this is already present. I have plans to remove this later once your PR is merged, and do some cleanup in the way this lint works, unrelated to your changes.
|
||
for (&id, impl_ids) in &impls.inherent_impls { | ||
if impl_ids.len() < 2 | ||
// Check for `#[allow]` on the type definition |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Check for `#[allow]` on the type definition | |
// Check for `#[expect]` or `#[allow]` on the type definition |
Add a config option
inherent-impl-lint-scope
to the lintmultiple_inherent_impl
to target a different scope according to people's needs. It can take three values:module
,file
, andcrate
(default).module
is the weakest option. It lints if there are two or more impls in the same module.file
is a bit stronger, since it lints if there are two or more impls in the same file. So, this triggers the lint (where it did not with module):crate
is the strongest of them; it triggers as soon as there are two or more impls anywhere in the crate. It is the current behaviour of the lint, so it's the default option.changelog: [
multiple_inherent_impl
] : Add config option (module
,file
orcrate
) to target specific scopefixes #14867